/*
 * led.c
 *
 * Created: 14/01/2013 15:23:05
 *  Author: marionse
 */ 

#include <avr/io.h>

#include "Board.h"
#include "ModSysTimer.h"
#include "ModLed.h"

/**
* \brief State of led
*/
#define LED_OFF			0x0U
#define LED_ON			0x1U
#define LED_BLINK		0x2U

/**
* \brief private variable
*/
static struct sLedState{
	struct  
	{
		Int8U logical	: 2U;
		Int8U real		: 2U;
	};
}led_state[NB_LED];

static TSysTime led_timer;

/**
* \brief private function
*/

static void ledIntSetOn( Int8U i_led );
static void ledIntSetOff( Int8U i_led );
static void ledIntToggle( Int8U i_led );


/**
* \brief initialized led
*
* \return TRUE if success
*/
Boolean ModLedInit( void )
{
	Int8U loop;
	// initialized to OFF state
	for( loop=0; loop<NB_LED; loop++ )
	{
		*(ledConfig[loop].io_port) &= ~(1U << ledConfig[loop].io_bit);
		ModLedSetOff( loop );
	}
	
	// get curent time
	led_timer = ModSysTimerGetValue();

	return TRUE;
}

/**
* \brief Tick function to update real state of led according to logical state
*/
void ModLedTick( void )
{
	TSysTime l_timer = ModSysTimerGetValue();
	
	if( ((TSysTime)(l_timer - led_timer)) > 300 )
	{
		Int8U loop;
	
		for( loop=0; loop<NB_LED; loop++ )
		{
			if( LED_BLINK == led_state[loop].logical )
			{
				ledIntToggle( loop );
			}
		}
				
		// uptade time
		led_timer = l_timer;
	}
}


/**
* \brief public function to set a led on
*/
void ModLedSetOn( Int8U i_led )
{
	// update logical state
	led_state[i_led].logical = LED_ON;
	// set real state
	ledIntSetOn( i_led );
}

/**
* \brief public function to set a led off
*/
void ModLedSetOff( Int8U i_led )
{
	// update logical state
	led_state[i_led].logical = LED_OFF;
	// set real state
	ledIntSetOff( i_led );
}

/**
* \brief public function to set a led blinking
*/
void ModLedSetBlink( Int8U i_led )
{
	// update logical state
	led_state[i_led].logical = LED_BLINK;
	// set real state
	ledIntToggle( i_led );
}

/************************************************************************/
/* PRIVATE PART                                                         */
/************************************************************************/

/**
* \brief private function to set a led on
*/
static void ledIntSetOn( Int8U i_led )
{
	*(ledConfig[i_led].io_ddr) |= (1U << ledConfig[i_led].io_bit);
	// update real state
	led_state[i_led].real = LED_ON;
}

/**
* \brief private function to set a led off
*/
static void ledIntSetOff( Int8U i_led )
{
	*(ledConfig[i_led].io_ddr) &= ~(1U << ledConfig[i_led].io_bit);
	// update real state
	led_state[i_led].real = LED_OFF;
}

/**
* \brief private function to toggle current real state of led
*/
static void ledIntToggle( Int8U i_led )
{
	if( LED_OFF == led_state[i_led].real )
	{
		ledIntSetOn( i_led );
	}
	else
	{
		ledIntSetOff( i_led );
	}
}
